package ipmsg.network;

import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.Socket;
import java.net.SocketException;

import ipmsg.IpmsgConstants;
import ipmsg.etc.FileLinkList;
import ipmsg.etc.FileNode;
import ipmsg.etc.GlobalVar;
import ipmsg.etc.UtilityGlobal;

/**
 * 发送文件的线程
 * 
 * @author idcomcn
 *
 */
public class SendFileDeamon extends Thread {
	private Socket socket;
	private DataOutputStream outputStream;
	private DataInputStream inputStream;

	public SendFileDeamon(Socket socket) {
		this.socket = socket;
	}

	public void run() {
		int fileKind = -1;
		int offset = 0;

		try {
			this.inputStream = new DataInputStream(new BufferedInputStream(this.socket.getInputStream()));
			this.outputStream = new DataOutputStream(this.socket.getOutputStream());
		} catch (IOException ex) {
			exit();
			return;
		}//end try
		
		System.out.println("idcomcn,inputStream:"+inputStream);

		for (int i = 0; i < 4; i++) {
			if (UtilityNet.readDelimiter(this.inputStream, 100) == null) {
				exit();
				return;
			} // end if
		} // end for

		String str = UtilityNet.readDelimiter(this.inputStream, 100);
		System.out.println("idcomcn,str:" + str);

		if (str == null) {
			exit();
			return;
		}
		int packetNo;
		try {
			packetNo = Integer.parseInt(str);
		} catch (NumberFormatException e) {
			exit();
			return;
		}

		if ((packetNo & IpmsgConstants.IPMSG_GETDIRFILES) == IpmsgConstants.IPMSG_GETDIRFILES) {
			fileKind = 2;
		} else if ((packetNo & IpmsgConstants.IPMSG_GETFILEDATA) == IpmsgConstants.IPMSG_GETFILEDATA) {
			fileKind = 1;
		} else {
			exit();
			return;
		}

		str = UtilityNet.readDelimiter(this.inputStream, 100);
		if (str == null) {
			exit();
			return;
		}
		try {
			packetNo = Integer.parseInt(str, 16);
		} catch (NumberFormatException e) {
			exit();
			return;
		}

		str = UtilityNet.readDelimiter(this.inputStream, 100);
		if (str == null) {
			exit();
			return;
		}
		try {
			offset = Integer.parseInt(str, 16);
		} catch (NumberFormatException e) {
			exit();
			return;
		}

		FileLinkList flist = GlobalVar.getFileList(packetNo);
		if ((flist == null) || (flist.isActive())) {
			exit();
			return;
		}

		if (!this.socket.getInetAddress().getHostAddress().equals(flist.getIp())) {
			exit();
			return;
		}

		FileNode fnode = (FileNode) flist.getFiles().get(offset);
		if ((fnode == null) || (fnode.isIsTransfered())) {
			exit();
			return;
		}

		if (fnode.getFileKind() != fileKind) {
			exit();
			return;
		}

		flist.setActive(true);
		switch (fileKind) {
		case 2:
			sendDir(flist, fnode);
			break;

		case 1:
			sendFile(flist, fnode);
			break;
		default:
			exit();
		}

	}

	private void sendDir(FileLinkList flist, FileNode fnode) {
		if (sendDir(new File(fnode.getFileName()))) {
			fnode.setIsTransfered(true);
			flist.setActive(false);
			if (flist.isTanstered())
				GlobalVar.delFileList(flist.getPacketNo());
		} else {
			flist.setActive(false);
		}
	}

	private boolean sendDir(File file) {
		if ((file == null) || ((!file.isDirectory()) && (!file.isFile()))) {
			return false;
		}

		if (!sendSubDir(file)) {
			return false;
		}
		if (file.isDirectory()) {
			File[] subdir = file.listFiles();
			int count = subdir.length;
			for (int i = 0; i < count; i++)
				if (!sendDir(subdir[i]))
					return false;
			if (!sendSubDir(null))
				return false;
		}
		return true;
	}

	private boolean sendSubDir(File file) {
		try {
			this.outputStream.write(createHeader(file).getBytes(GlobalVar.CHARACTER_ENCODING));

			if ((file != null) && (file.isFile()) && (!sendFile(file.getPath()))) {
				return false;
			}
			return true;
		} catch (IOException ex) {
		}
		return false;
	}

	private String createHeader(File file) {
		String res;
		if (file == null) {
			res = ":.:0:" + Integer.toHexString(3) + ":0:";
		} else {
			res = ":" + file.getName() + ":" + Long.toHexString(file.length()) + ":"
					+ (file.isDirectory() ? Integer.toHexString(2) : Integer.toHexString(1)) + ":0:";
		}

		try {
			return UtilityGlobal.dec2Hex(res.getBytes(GlobalVar.CHARACTER_ENCODING).length + 8) + res;
		} catch (UnsupportedEncodingException ex) {
		}
		return null;
	}

	private void sendFile(FileLinkList flist, FileNode fnode) {
		if (sendFile(fnode.getFileName())) {
			fnode.setIsTransfered(true);
			flist.setActive(false);
			if (flist.isTanstered())
				GlobalVar.delFileList(flist.getPacketNo());
		} else {
			flist.setActive(false);
		}
	}

	private boolean sendFile(String filePath) {
		try {
			DataInputStream fis = new DataInputStream(new BufferedInputStream(new FileInputStream(filePath)));

			byte[] buf = new byte[8092];

			int read = 0;
			for (;;) {
				if (fis != null) {
					read = fis.read(buf);
				}
				if (read == -1) {
					break;
				}
				this.outputStream.write(buf, 0, read);
			}
			this.outputStream.flush();
			fis.close();
			return true;
		} catch (SocketException e) {
			return false;
		} catch (IOException e) {
		}
		return false;
	}

	private void exit() {
		try {
			this.inputStream.close();
			this.outputStream.close();
			this.socket.close();
		} catch (IOException ex) {
		}
	}
}
